package com.comunity_cloud.client.model.communication.packet;

import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;

import com.comunity_cloud.client.model.fetch_file.FetchFileHeader;
import com.comunity_cloud.client.model.fetch_file.FetchFileResponse;
import com.comunity_cloud.client.model.file_list.SendMeFilesHeader;
import com.comunity_cloud.client.model.file_list.SendMeFilesResponse;
import com.comunity_cloud.client.model.upload_file.UploadFileHeader;


public abstract class PeerPacketHeader{
	
	protected static final int COMMON_HEADER_SIZE = 4 + 4 + 4 +  8;
	
	public static Map<Type,Class<? extends PeerPacketHeader>> TypesMap = new HashMap<>();
	
	static {
		TypesMap.put(Type.SEND_ME_FILES, SendMeFilesHeader.class);
		TypesMap.put(Type.SEND_ME_FILES_RESPONSE, SendMeFilesResponse.class);
		TypesMap.put(Type.UPLOAD_FILE, UploadFileHeader.class);
		TypesMap.put(Type.FETCH_FILE, FetchFileHeader.class);
		TypesMap.put(Type.FETCH_FILE_RESPONSE, FetchFileResponse.class);
	}
	
	public enum Type {
		SEND_ME_FILES,
		SEND_ME_FILES_RESPONSE,
		UPLOAD_FILE,
		FETCH_FILE,
		FETCH_FILE_RESPONSE
	}
	
	protected int headerLength;
	
	protected Type type;
	
	protected int payloadSize;
	
	protected long communityId;
	
	
	protected byte[] bytes;
	
	protected ByteBuffer byteBuffer;
	
	
	public Type getType() {
		return type;
	}
	
	public void setType(Type type) {
		this.type = type;
	}
	
	public long getCommunityId() {
		return communityId;
	}
	
	public void setCommunityId(long communityId) {
		this.communityId = communityId;
	}
	
	public byte[] asByteArray() {
		convertToBytesInner();
		return bytes;
	}
	
	private void convertToBytesInner(){
		headerLength = COMMON_HEADER_SIZE+headerLength();
		if(bytes == null || bytes.length < headerLength) {
			bytes = new byte[headerLength];
			byteBuffer = ByteBuffer.wrap(bytes);
		} 
		byteBuffer.rewind();
		byteBuffer.putInt(headerLength);
		byteBuffer.putInt(payloadSize);
		byteBuffer.putInt(type.ordinal());
		byteBuffer.putLong(communityId);
		convertToBytes();
	}

	protected abstract void convertToBytes(); 
	
	protected abstract int headerLength();
	
	public void fromByteArray(byte[] bytes){
		this.bytes = bytes;
		byteBuffer = ByteBuffer.wrap(bytes);
		headerLength = byteBuffer.getInt();
		byteBuffer.limit(headerLength);
		payloadSize = byteBuffer.getInt();
		type = Type.values()[byteBuffer.getInt()];
		communityId = byteBuffer.getLong();
		fromBytes();
	}
	
	public long getHeaderLength() {
		return headerLength;
	}
	
	protected abstract void fromBytes();
	
	
	public int getPayloadSize() {
		return payloadSize;
	}
	
	public void setPayloadSize(int payloadSize) {
		this.payloadSize = payloadSize;
	}
	
	public static int headerLengthFromBytes(ByteBuffer byteBuffer) {
		return byteBuffer.getInt();
	}
	
	public static int payloadSizeFromBytes(ByteBuffer byteBuffer) {
		return byteBuffer.getInt();
	}
	
	public static Type typeFromBytes(ByteBuffer byteBuffer) {
		return Type.values()[byteBuffer.getInt()];
	}

	
	
}
